#!/usr/bin/env node

/**
 * 直律OA系统 - 端到端测试运行脚本
 *
 * 此脚本用于运行Cypress端到端测试，支持：
 * 1. 运行所有测试模块
 * 2. 运行指定模块的测试
 * 3. 列出所有可用的测试模块
 * 4. 自动安装依赖、启动/关闭服务器、生成报告
 *
 * 使用方法:
 * node scripts/run-full-e2e-tests.js [options]
 * 或通过package.json脚本: npm run test:full-e2e [options]
 */

import { spawn, spawnSync } from 'child_process'
import fs from 'fs'
import path from 'path'
import process from 'process'

// 定义颜色输出
const colors = {
  reset: '\x1b[0m',
  green: '\x1b[32m',
  red: '\x1b[31m',
  yellow: '\x1b[33m',
  blue: '\x1b[34m',
  cyan: '\x1b[36m',
}

// 打印带颜色的日志
function log(message, color = colors.reset) {
  console.log(`${color}${message}${colors.reset}`)
}

function logSuccess(message) {
  log(`✓ ${message}`, colors.green)
}

function logError(message) {
  log(`✗ ${message}`, colors.red)
}

function logWarning(message) {
  log(`⚠ ${message}`, colors.yellow)
}

function logInfo(message) {
  log(`ℹ ${message}`, colors.blue)
}

function logDebug(message, details = '') {
  // 仅在开发环境下显示调试信息
  if (process.env.NODE_ENV === 'development') {
    log(`🗒️ ${message}`, colors.cyan)
    if (details) {
      log(`   ${details}`, colors.cyan)
    }
  }
}

function logTitle(message) {
  log('\n' + '='.repeat(50), colors.cyan)
  log(' '.repeat(20) + message, colors.cyan)
  log('='.repeat(50) + '\n', colors.cyan)
}

// 显示帮助信息
function showHelp() {
  logTitle('直律OA系统端到端测试工具')
  log('用法: npm run test:full-e2e [options]\n')
  log('选项:')
  log('  --help, -h                显示帮助信息')
  log('  --all                     运行所有测试模块')
  log('  --module <module-name>    运行指定模块的测试（如: --module 人事管理）')
  log('  --list                    列出所有可用的测试模块')
  log('\n示例:')
  log('  npm run test:full-e2e -- --all')
  log('  npm run test:full-e2e -- --module 人事管理')
  log('  npm run test:full-e2e -- --list')
}

// 列出所有测试模块
function listModules() {
  const modulesDir = path.join(__dirname, '..', 'cypress', 'e2e', 'modules')
  if (!fs.existsSync(modulesDir)) {
    logError('模块测试目录不存在')
    return []
  }

  const files = fs
    .readdirSync(modulesDir)
    .filter(file => file.endsWith('.cy.ts') && file !== 'all-modules-test.cy.ts')

  const modules = files.map(file => {
    const moduleName = file.replace('-tests.cy.ts', '')
    return moduleName
  })

  logTitle('可用的测试模块')
  modules.forEach((module, index) => {
    log(`  ${index + 1}. ${module}`)
  })
  log(`\n共 ${modules.length} 个测试模块`)

  return modules
}

// 创建报告目录
function createReportDir() {
  const reportDir = path.join(__dirname, '..', 'cypress', 'reports')
  if (!fs.existsSync(reportDir)) {
    fs.mkdirSync(reportDir, { recursive: true })
    logSuccess('测试报告目录已创建')
  }
  return reportDir
}

// 启动开发服务器 - 增强版错误处理
function startDevServer() {
  logInfo('启动前端开发服务器...')

  // 在Windows环境中，确保使用正确的npm命令路径
  const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'

  try {
    // 设置环境变量
    const env = Object.create(process.env)
    env.NODE_ENV = 'development'

    const server = spawn(npmCommand, ['run', 'dev'], {
      stdio: ['ignore', 'pipe', 'pipe'],
      env,
    })

    // 捕获服务器输出
    server.stdout.on('data', data => {
      process.stdout.write(`[SERVER] ${data}`)
    })

    server.stderr.on('data', data => {
      process.stderr.write(`[SERVER ERROR] ${data}`)
    })

    // 监听服务器关闭事件
    server.on('close', code => {
      if (code !== 0) {
        logError(`服务器意外关闭，退出码: ${code}`)
        process.exit(1)
      }
    })

    server.on('error', error => {
      logError('启动开发服务器失败:', error.message)
      if (error.code === 'ENOENT') {
        logWarning('npm命令未找到，请确保npm已正确安装并添加到系统PATH中')
        logInfo('尝试使用已有的开发服务器或跳过服务器启动...')
      }
    })

    return server
  } catch (error) {
    logError('启动开发服务器时发生异常:', error.message)
    logWarning('将尝试跳过开发服务器启动，直接进行测试')
    return null // 返回null表示服务器启动失败
  }
}

// 等待服务器启动
function waitForServerReady() {
  return new Promise((resolve, reject) => {
    logInfo('等待服务器启动完成...')

    let attempts = 0
    const maxAttempts = 30 // 最多等待30秒
    const checkInterval = 1000 // 每秒检查一次

    const checkServer = () => {
      attempts++

      if (attempts > maxAttempts) {
        reject(new Error('服务器启动超时'))
        return
      }

      // 发送HTTP请求检查服务器是否可用
      import('http')
        .then(http => {
          const req = http.get('http://localhost:8081', res => {
            if (res.statusCode === 200) {
              logSuccess('服务器已成功启动')
              resolve()
            } else {
              setTimeout(checkServer, checkInterval)
            }
          })

          req.on('error', () => {
            setTimeout(checkServer, checkInterval)
          })

          req.end()
        })
        .catch(() => {
          setTimeout(checkServer, checkInterval)
        })
    }

    // 开始检查
    setTimeout(checkServer, checkInterval)
  })
}

// 运行Cypress测试
export function runCypressTests(testType, moduleName = '') {
  logTitle('开始运行Cypress端到端测试')

  // 确定测试文件路径
  let specPath = 'cypress/e2e/full-automation-test-suite.cy.ts'

  if (testType === 'all') {
    specPath = 'cypress/e2e/modules/all-modules-test.cy.ts'
    logInfo('将运行所有模块测试')
  } else if (testType === 'module') {
    specPath = `cypress/e2e/modules/${moduleName}-tests.cy.ts`
    logInfo(`将运行 ${moduleName} 模块测试`)

    // 检查模块文件是否存在
    const fullSpecPath = path.join(__dirname, '..', specPath)
    if (!fs.existsSync(fullSpecPath)) {
      logError(`模块测试文件不存在: ${fullSpecPath}`)
      logInfo('使用 --list 查看所有可用的测试模块')
      return false
    } else {
      logSuccess(`找到了测试文件: ${fullSpecPath}`)
    }
  }

  const reportDir = createReportDir()

  // 运行Cypress测试
  logInfo('准备执行Cypress命令...')
  logDebug(`测试文件路径: ${specPath}`)

  try {
    // 先检查Cypress是否可执行
    const cypressCheck = spawnSync('npx', ['cypress', '--version'], { stdio: 'pipe' })
    if (cypressCheck.status !== 0) {
      logError('Cypress命令执行失败，输出:', cypressCheck.stderr.toString())
      logWarning('尝试使用简化的Cypress命令运行测试...')

      // 尝试简化的命令，不指定报告器
      const simplifiedResult = spawnSync(
        'npx',
        [
          'cypress',
          'run',
          '--spec',
          specPath,
          '--headed', // 使用有界面模式，有助于调试
        ],
        {
          stdio: 'inherit',
        }
      )

      return simplifiedResult.status === 0
    } else {
      logSuccess('Cypress版本信息:', cypressCheck.stdout.toString())
    }

    // 正常运行Cypress测试
    const result = spawnSync(
      'npx',
      [
        'cypress',
        'run',
        '--spec',
        specPath,
        '--reporter',
        'mochawesome',
        '--reporter-options',
        `reportDir=${reportDir},overwrite=false,html=true,json=true`,
      ],
      {
        stdio: 'inherit',
      }
    )

    logDebug(`Cypress测试命令退出码: ${result.status}`)
    return result.status === 0
  } catch (error) {
    logError('运行Cypress测试时发生异常:', error.message)

    // 作为最后的尝试，直接调用cypress命令（不通过npx）
    try {
      logWarning('尝试直接调用cypress命令...')
      const directResult = spawnSync('cypress', ['run', '--spec', specPath, '--headed'], {
        stdio: 'inherit',
      })

      return directResult.status === 0
    } catch (directError) {
      logError('直接调用cypress命令也失败:', directError.message)
      return false
    }
  }
}

// 生成汇总报告
function generateReportSummary(testType, moduleName = '') {
  logInfo('生成测试报告汇总...')

  // 尝试合并和生成报告，但不强制依赖
  try {
    // 检查mochawesome-merge命令是否可用
    const { status } = spawnSync('npx', ['mochawesome-merge', '--version'], { stdio: 'ignore' })

    if (status === 0) {
      // 合并报告
      logInfo('正在合并测试报告...')
      spawnSync(
        'npx',
        ['mochawesome-merge', 'cypress/reports/*.json', '>', 'cypress/reports/merged-report.json'],
        {
          shell: true,
          stdio: 'inherit',
        }
      )

      // 生成HTML报告
      logInfo('正在生成HTML报告...')
      spawnSync(
        'npx',
        [
          'marge',
          'cypress/reports/merged-report.json',
          '--reportDir',
          'cypress/reports',
          '--inline',
          '--overwrite',
        ],
        {
          shell: true,
          stdio: 'inherit',
        }
      )

      logSuccess('测试报告已生成: cypress/reports/index.html')
    } else {
      throw new Error('mochawesome-merge不可用')
    }
  } catch (error) {
    logWarning('跳过报告合并步骤，因为mochawesome-merge可能未安装')
  }

  // 生成自定义报告
  const summaryReportPath = path.join(__dirname, '..', 'cypress', 'reports', 'summary.md')
  let summaryContent = `# 端到端测试报告汇总\n\n`
  summaryContent += `**测试时间**: ${new Date().toLocaleString()}\n`
  summaryContent += `**测试环境**: 本地开发环境\n`

  if (testType === 'all') {
    summaryContent += `**测试类型**: 全量测试\n`
    summaryContent += `**测试覆盖**: 直律OA系统所有核心功能模块\n`
  } else if (testType === 'module') {
    summaryContent += `**测试类型**: 模块测试\n`
    summaryContent += `**测试模块**: ${moduleName}\n`
  } else {
    summaryContent += `**测试类型**: 单文件测试\n`
    summaryContent += `**测试覆盖**: 直律OA系统核心功能模块\n`
  }

  summaryContent += '\n## 测试结果\n\n'
  summaryContent += '测试已完成，请查看详细的测试日志和报告文件。\n'

  fs.writeFileSync(summaryReportPath, summaryContent, 'utf8')
  logSuccess(`测试报告汇总已生成: ${summaryReportPath}`)
}

// 安装测试依赖
function installTestDependencies() {
  logInfo('检查测试环境...')

  // 检查Cypress是否安装 - 简化版，添加更多错误处理
  try {
    const { status } = spawnSync('npx', ['cypress', '--version'], { shell: false, stdio: 'ignore' })
    if (status !== 0) {
      logWarning('警告: Cypress 可能未正确安装，但将尝试继续运行测试...')
      logInfo('如果测试失败，请尝试手动安装: npm install --save-dev cypress')
    } else {
      logSuccess('Cypress已安装')
    }
  } catch (error) {
    logError('检查Cypress安装状态时出错:', error.message)
    logInfo('将尝试跳过依赖检查直接运行测试...')
  }
}

// 主函数
async function main() {
  let server = null

  try {
    logTitle('直律OA系统 - 端到端测试')

    // 解析命令行参数
    const args = process.argv.slice(2)

    // 显示帮助信息
    if (args.includes('--help') || args.includes('-h')) {
      showHelp()
      process.exit(0)
    }

    // 列出所有模块
    if (args.includes('--list')) {
      listModules()
      process.exit(0)
    }

    // 确定测试类型
    let testType = '' // 默认单文件测试
    let moduleName = ''

    if (args.includes('--all')) {
      testType = 'all'
    } else if (args.includes('--module')) {
      testType = 'module'
      const moduleIndex = args.indexOf('--module') + 1
      if (moduleIndex < args.length) {
        moduleName = args[moduleIndex]
      } else {
        logError('请指定要测试的模块名称')
        showHelp()
        process.exit(1)
      }
    }

    // 1. 安装测试依赖
    installTestDependencies()

    // 2. 启动开发服务器并处理可能的失败
    let serverReady = false
    try {
      server = startDevServer()

      if (server) {
        try {
          // 3. 等待服务器就绪
          await waitForServerReady()
          serverReady = true
        } catch (serverWaitError) {
          logError(`等待服务器就绪失败: ${serverWaitError.message}`)
          logWarning('将尝试跳过服务器检查，直接进行测试（假设已有服务器在运行）')
        }
      } else {
        logWarning('开发服务器未启动，将尝试直接运行测试（假设已有服务器在运行）')
      }
    } catch (serverStartError) {
      logError(`启动服务器失败: ${serverStartError.message}`)
      logWarning('将尝试跳过服务器启动，直接进行测试')
    }

    // 4. 运行测试，即使服务器可能未正常启动
    let testsPassed = false
    try {
      testsPassed = runCypressTests(testType, moduleName)
    } catch (testError) {
      logError(`运行测试时出错: ${testError.message}`)
    }

    // 5. 生成报告
    try {
      generateReportSummary(testType, moduleName)
    } catch (reportError) {
      logWarning(`生成报告时出错: ${reportError.message}`)
    }

    // 6. 清理并退出
    try {
      if (server) {
        server.kill()
        logSuccess('开发服务器已关闭')
      }
    } catch (cleanupError) {
      logWarning(`关闭服务器时出错: ${cleanupError.message}`)
    }

    logTitle(testsPassed ? '测试全部通过！' : '测试失败！')

    process.exit(testsPassed ? 0 : 1)
  } catch (error) {
    logError(`严重错误: ${error.message}`)

    // 确保服务器被关闭
    if (server) {
      try {
        server.kill()
      } catch (cleanupError) {
        logWarning(`关闭服务器时出错: ${cleanupError.message}`)
      }
    }

    process.exit(1)
  }
}

// 执行主函数
import { fileURLToPath } from 'url'
import { dirname } from 'path'

// 在ES模块中检查是否直接运行脚本
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

// 检查是否直接运行此脚本
if (process.argv[1] === __filename) {
  main()
}

export default {
  runFullE2ETests: main,
  runCypressTests,
}
